package logger

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/gogf/gf/os/glog"
	rotatelogs "github.com/lestrrat-go/file-rotatelogs"
	"github.com/rifflock/lfshook"
	"github.com/sirupsen/logrus"
	"gitlab.local/golibrary/utils"
	"os"
	"path/filepath"
	"strings"
	"time"
)

const (
	AccessLogFile = "/var/log/tos/access%s.log" // 记录路由日志
	ErrorLogFile  = "/var/log/tos/error.log"    // 记录错误日志
)

type myFormatter struct {
	logrus.TextFormatter
}

func (f *myFormatter) SortData(fields logrus.Fields) []string {
	result := make([]string, 0)
	result = append(result, fmt.Sprintf("%3v", fields["status_code"]))
	result = append(result, fmt.Sprintf("%6v", fields["req_method"]))
	result = append(result, fmt.Sprintf("%15v", fields["client_ip"]))
	result = append(result, fmt.Sprintf("%v", fields["req_uri"]))
	result = append(result, fmt.Sprintf("%v", fields["latency_time"]))
	result = append(result, fmt.Sprintf("%v", fields["req_agent"]))
	return result
}

func (f *myFormatter) Format(entry *logrus.Entry) ([]byte, error) {
	result := make([]string, 0)
	result = append(result, strings.ToUpper(entry.Level.String()))
	result = append(result, entry.Time.Format(f.TimestampFormat))
	result = append(result, f.SortData(entry.Data)...)
	result = append(result, entry.Message)
	return []byte(strings.Join(result, " | ") + "\n"), nil
}

type Service struct {
	Logger    *logrus.Logger
	fileName  string
	logWriter *rotatelogs.RotateLogs
	format    myFormatter //定制日志格式
}

func New() *Service {
	logDir := filepath.Dir(AccessLogFile)
	if !utils.Exists(logDir) {
		_ = os.Mkdir(logDir, 0755)
	}
	Instance := &Service{
		Logger:   logrus.New(),
		fileName: fmt.Sprintf(AccessLogFile, ""),
		format: myFormatter{
			logrus.TextFormatter{
				TimestampFormat: "2006-01-02 15:04:05",
			},
		},
	}
	Instance.logWriter, _ = rotatelogs.New(
		// 分割后的文件名称
		fmt.Sprintf(AccessLogFile, ".%Y%m%d"),
		// 生成软链，指向最新日志文件
		rotatelogs.WithLinkName(Instance.fileName),
		// 设置最大保存时间(7天)
		rotatelogs.WithMaxAge(7*24*time.Hour),
		// 设置日志切割时间间隔(1天)
		rotatelogs.WithRotationTime(24*time.Hour),
	)
	//设置日志级别
	logLevel := logrus.WarnLevel
	_ = glog.SetLevelStr("INFO")
	if os.Getenv("__Debug") == "true" {
		logLevel = logrus.DebugLevel
		_ = glog.SetLevelStr("DEV")
	}
	Instance.Logger.SetLevel(logLevel)
	Instance.Logger.SetFormatter(&Instance.format)
	glog.SetWriter(Instance.logWriter)
	gin.DefaultWriter = Instance.logWriter
	gin.DefaultErrorWriter = Instance.logWriter

	return Instance
}

func (m *Service) SetLogger() gin.HandlerFunc {
	// 设置 rotatelogs
	writeMap := lfshook.WriterMap{
		logrus.InfoLevel:  m.logWriter,
		logrus.FatalLevel: m.logWriter,
		logrus.DebugLevel: m.logWriter,
		logrus.WarnLevel:  m.logWriter,
		logrus.ErrorLevel: m.logWriter,
		logrus.PanicLevel: m.logWriter,
	}
	m.Logger.AddHook(lfshook.NewHook(writeMap, &m.format))

	return func(c *gin.Context) {
		//开始时间
		startTime := time.Now()
		//处理请求
		c.Next()
		//结束时间
		endTime := time.Now()
		// 执行时间
		latencyTime := endTime.Sub(startTime)
		//请求方式
		reqMethod := c.Request.Method
		//请求路由
		reqUrl := c.Request.RequestURI
		//状态码
		statusCode := c.Writer.Status()
		//请求ip
		clientIP := c.ClientIP()
		//请求来源
		agentName := c.Request.UserAgent()
		// 日志格式
		entry := m.Logger.WithFields(logrus.Fields{
			"status_code":  statusCode,
			"latency_time": latencyTime,
			"client_ip":    clientIP,
			"req_method":   reqMethod,
			"req_uri":      reqUrl,
			"req_agent":    agentName,
		})
		//读取上下文中的状态
		err, _ := c.Get("status")
		if err == nil {
			entry.Info()
		} else {
			entry.Error(err)
		}
	}
}

func IsDebug() bool {
	return os.Getenv("__Debug") == "true"
}

func DebugPrintln(s string) {
	if os.Getenv("__Debug") == "true" {
		glog.Info(s)
	}
}

func DebugPrintf(s string, arg ...string) {
	if os.Getenv("__Debug") == "true" {
		glog.Printf(s, arg)
	}
}

func Errorln(s string) {
	fmt.Fprintf(os.Stderr, "%s\n", s)
}

func Errorf(s string, arg ...string) {
	fmt.Fprintf(os.Stderr, "%s\n", fmt.Sprintf(s, arg))
}
